﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using WeChatParking.Entity.DBGen;

namespace WeChatParking.Core.BLL
{
    public interface IWXMsgNotify
    {
        void SendAll();

        void Send(WXNotifyMsg msg);
    }
    public abstract class WxMsgNotify : IWXMsgNotify
    {
        private IList<WXMsgConfig> tplConfig = null;

        private Regex PLACEHOLD_REG = new Regex(@"\{#(.*?)\#}", RegexOptions.Compiled);

        public WxMsgNotify()
        {
            using (var ctx = Repository.DbContext.Create())
            {
                tplConfig = ctx.GetList<WXMsgConfig>(null).ToList();
            }
        }

        protected string WxMsgApiUrl { get; set; }

        public abstract string QueryAllForSendSql { get; }

        public abstract string ConvertToApiBody(WXNotifyMsg msg, WXMsgConfig config);

        private Dictionary<string, string> GetPlaceholdWords(string str)
        {
            Dictionary<string, string> phw = new Dictionary<string, string>();
            var matchs = PLACEHOLD_REG.Matches(str);
            foreach (Match m in matchs)
            {
                if (phw.ContainsKey(m.Value) == false)
                {
                    phw[m.Value] = m.Groups[1].Value;
                }
            }
            return phw;
        }

        protected string FormatMsg(string jsonData, string tpl)
        {
            var data = JObject.Parse(jsonData);
            var words = GetPlaceholdWords(tpl);
            foreach (var w in words)
            {
                var token = data[w.Value];
                tpl = tpl.Replace(w.Key, token == null ? string.Empty : token.ToString());
            }
            return tpl;
        }


        public void SendAll()
        {
            IList<WXNotifyMsg> msgList = null;
            using (var ctx = Repository.DbContext.Create())
            {
                msgList = ctx.GetListBySql<WXNotifyMsg>(QueryAllForSendSql, null).ToList();
            }
            if (msgList != null && msgList.Count > 0)
            {
                foreach (var m in msgList)
                {
                    Send(m);
                }
                LogHelper.Info(string.Format("处理 {0} 条微信消息", msgList.Count), Entity.Enums.LogType.WxNotifyMsg);
            }
        }

        private void SaveState(int pkId, byte state, string stateMsg)
        {
            var updateSql = @"update WXNotifyMsg set 
                    LeaveTry=LeaveTry-1, 
                    SendState=@State, 
                    StateMsg=@Msg, 
                    SendTime=@Time
                where PkId=@PkId";

            var ps = new Dapper.DynamicParameters();
            ps.Add("@State", state, DbType.Byte, ParameterDirection.Input);
            ps.Add("@Msg", stateMsg, DbType.String, ParameterDirection.Input);
            ps.Add("@Time", DateTime.Now, DbType.DateTime, ParameterDirection.Input);
            ps.Add("@PkId", pkId, DbType.Int32, ParameterDirection.Input);

            using (var ctx = Repository.DbContext.Create())
            {
                ctx.Execute(updateSql, ps, CommandType.Text);
            }
        }

        public void Send(WXNotifyMsg msg)
        {
            try
            {
                var tplItem = tplConfig.FirstOrDefault(t => t.MsgType == msg.MsgType);
                var msgBody = ConvertToApiBody(msg, tplItem);

                if (string.IsNullOrEmpty(msgBody))
                {
                    msg.SendState = (byte)1;
                    msg.StateMsg = "未配置消息模板";
                }
                else
                {
                    var accessToken = new Core.Payment.WeixinPay.WxpayClient().GetAccessToken();
                    var url = string.Format(WxMsgApiUrl, accessToken);
                    var res = new WebUtils().DoPost(url, msgBody, "UTF-8");
                    var result = Util.Conv.ParseJson<WeChatParking.Entity.DBGen.WxApiResult>(res);

                    msg.SendState = result.errcode == "0" ? (byte)2 : (byte)1;
                    msg.StateMsg = result.errmsg;
                }
            }
            catch (Exception ex)
            {
                msg.SendState = (byte)0;
                msg.StateMsg = ex.Message;
            }
            SaveState(msg.PkId, msg.SendState, msg.StateMsg);
        }
    }

    public class WxMsgNotify_Fuwuhao : WxMsgNotify
    {
        public WxMsgNotify_Fuwuhao()
        {
            WxMsgApiUrl = SystemConfig.GetConfigValue(Entity.Enums.SystemConfig.WxTemplatMsgUrl);
        }

        public override string QueryAllForSendSql
        {
            get
            {
                return @" SELECT  * FROM WXNotifyMsg WHERE SendState=0 AND LeaveTry>0";
            }
        }


        public override string ConvertToApiBody(WXNotifyMsg msg, WXMsgConfig config)
        {
            if (config == null || string.IsNullOrEmpty(config.FWHContentTpl) || string.IsNullOrEmpty(config.FWHTemplateId))
            {
                return null;
            }

            var msgBody = FormatMsg(msg.Content, config.FWHContentTpl)
                .Replace("#touser#", msg.OpenId)
                .Replace("#template_id#", config.FWHTemplateId);
            return msgBody;
        }
    }

}
